#include "Debug.h"
#include "VertexBase.h"
#include "SubMesh.h"

VertexBase::VertexBase(int _vertexNumber, MPoint _position)
{
	vertexNumber = _vertexNumber;
	position = _position;
	maxDistortionSubMesh = NULL;
	boundaryVertex = false;
}

VertexBase::VertexBase()
{
}


VertexBase::~VertexBase()
{
}

double VertexBase::getAngle(TriangleBase* in)
{
	return parents[in].angle;
}

void VertexBase::setAngle(TriangleBase* in, double newAngle )
{
	parents[in].angle = newAngle;
}

double VertexBase::getAngularDistortionInTriangle(TriangleBase* in)
{
	double weight = parents[in].weight;
	double angle = parents[in].angle;
	double optimumAngle = parents[in].optimumAngle;

	double dist = ( pow((angle- optimumAngle), 2) ) * weight;
	return dist;
}

double VertexBase::reconstructability()
{
	double nextAngles = 1;
	double prevAngles = 1;
	for (map<TriangleBase*, angleSet>::iterator it=parents.begin(); it!=parents.end(); ++it)
	{
		nextAngles = nextAngles * sin(it->first->getNextAngle(this)*M_PI/180); 
		prevAngles = prevAngles * sin(it->first->getPrevAngle(this)*M_PI/180); 
	}
	return nextAngles - prevAngles;
}

void VertexBase::addTriangleParent(TriangleBase* parent, double _originalAngle)
{
	angleSet set;
	set.angle = _originalAngle;
	set.originalAngle = _originalAngle;

	parents[parent] = set;
}

void VertexBase::setOptimalAngle(TriangleBase* parent)
{
	if(onBoundary())
		parents[parent].optimumAngle = parents[parent].originalAngle;
	else
	{
		double lowerTerm = 0;
		for (map<TriangleBase*, angleSet>::iterator it=parents.begin(); it!=parents.end(); ++it)	
			lowerTerm += it->second.originalAngle;	
		parents[parent].optimumAngle = parents[parent].originalAngle * (360 / lowerTerm);
	}
	parents[parent].weight = pow(parents[parent].optimumAngle, -2);
}

MPoint VertexBase::getPos()
{
	return position;
}

void VertexBase::cleanMemory()
{
	delete maxDistortionSubMesh;
}

int VertexBase::getNum()
{
	return vertexNumber;
}

double VertexBase::sumAngles()
{
	double total = 0;
	for (map<TriangleBase*, angleSet>::iterator it=parents.begin(); it!=parents.end(); ++it)	
		total += it->second.angle;	
	return total;
}


void VertexBase::printAllContents()
{
	cout << vertexNumber << " B:" << boundaryVertex;
	for (map<TriangleBase*, angleSet>::iterator it=parents.begin(); it!=parents.end(); ++it)	
		cout << "\t tri:" << it->first->getNum() << " Angle:" << it->second.angle << "\t";
	cout << endl;
}

void VertexBase::printContents(TriangleBase* lookup)
{
	cout << vertexNumber << " "  << parents[lookup].angle;
}



void VertexBase::setDistortion(double _distortion, int _radius,  double _R, SubMesh* sm)
{
	distortion = _distortion;
	radius = _radius;
	R = _R;
	maxDistortionSubMesh = sm;
	if(R < 0)
		R = 0;
}

int VertexBase::getRadius()
{
	return radius;
}

double VertexBase::getDistortion()
{
	return distortion;
}

void VertexBase::setRad0Distortion(double _distortion)
{
	rad0Distortion =_distortion;
}

double VertexBase::getRad0Distortion()
{
	return rad0Distortion;
}

double VertexBase::getR()
{
	return R;
}

void VertexBase::setR(double _R)
{
	R = _R;
}

SubMesh* VertexBase::getSubMesh()
{
	return maxDistortionSubMesh;
}

void VertexBase::setDistortionToRad0()
{
	distortion = rad0Distortion;
	radius = 0;
	R = 0;
}

void VertexBase::setBoundary(bool input)
{
	boundaryVertex = input;
}

bool VertexBase::onBoundary()
{
	return boundaryVertex;
}

void VertexBase::getConnectedEdges(vector<int>& output)
{
	output = connectedEdges;
}


void VertexBase::setConnectedEdges(MIntArray input)
{
	for(uint i=0; i< input.length(); i++)
		connectedEdges.push_back(input[i]);
}

vector<TriangleBase*> VertexBase::getAdjacentTriangles()
{
	vector<TriangleBase*> adjacents;
	for (map<TriangleBase*, angleSet>::iterator it=parents.begin(); it!=parents.end(); ++it)	
		adjacents.push_back(it->first);
	return adjacents;
}

VertexBase::uvPoint VertexBase::getUVPoint(TriangleBase* in)
{
	try
	{
		return uvs.at(in);
	}
	catch (exception e)
	{
		cout << "Error, uv points asked for non existent member" << endl;
		uvPoint error;
		error.u = -1000;
		error.v = -1000;
		return error;
	}
}

void VertexBase::setUVPoint(double newU, double newV, TriangleBase* in)
{	
	uvs[in].u = newU;
	uvs[in].v = newV;	
}

bool VertexBase::isFixed(TriangleBase* in)
{
	try	
	{
		uvs.at(in);	
	}
	catch (exception e)	
	{
		return false;	
	}
	return true;
}

void VertexBase::averageOutPositions(TriangleBase* in, TriangleBase* in2, double newU, double newV)
{
		double averageU = (uvs[in2].u  + newU )/2;
		double averageV = (uvs[in2].v  + newV)/2;

		uvs[in].u = averageU;	
		uvs[in].v = averageV;
		uvs[in2].u = averageU;	
		uvs[in2].v = averageV;
	
}


vector<VertexBase*> VertexBase::getAdjacentVertices()
{
	vector<TriangleBase*> adjTris = getAdjacentTriangles();
	set<VertexBase*> adjVerts;
	for(int i=0; i<adjTris.size(); i++)
	{
		vector<VertexBase*> verts = adjTris[i]->getCorners();
		for(int j=0; j<verts.size(); j++)		
			adjVerts.insert(verts[j]);		
	}
	vector<VertexBase*> adjVertsVector;
	for(set<VertexBase*>::iterator i  = adjVerts.begin(); i!=adjVerts.end(); i++)	
		if( (*i)->getNum() != vertexNumber )
			adjVertsVector.push_back(*i);
	
	return adjVertsVector;
}


double VertexBase::getOptimumAngle(TriangleBase* in)
{
	return parents[in].optimumAngle;
}

double VertexBase::getWeight(TriangleBase* in)
{
	return parents[in].weight;
}

map<TriangleBase*, VertexBase::uvPoint> VertexBase::getAllUVs()
{
	return uvs;
}